#include	<system/kernel.h>
#include	<system/libk.h>
#include	<types.h>

#define	RELEASED	0x80
#define	KEY_ESC		0x01
#define	KEY_SHIFT	0x2A
#define	KEY_CTRL	0x1D
#define	KEY_ALT		0x38
#define	KEY_DEL		0x53
#define	KEY_F1		0x3B
#define	KEY_F2		KEY_F1 + 1
#define	KEY_F3		KEY_F2 + 1
#define	KEY_F4		KEY_F3 + 1

static	uchar_t	flags = 0;
static	uchar_t	lastkey = 0;

#define	SHIFT_FLAG	1
#define	ALT_FLAG	(SHIFT_FLAG << 1)
#define	CTRL_FLAG	(SHIFT_FLAG << 2)

void	set_flag(uchar_t f)
{
	flags |= f;
}

void	unset_flag(uchar_t f)
{
	flags ^= f;
}

static uint_t	shifted	= 0, controled = 0;

/* mapa para teclado ABNT2 pt_BR caixa baixa */
const char_t	lower_pt_BR[0xFF] =
{
	0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 0, 
	'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '´', '[', 0, 0, 'a', 's',
	'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ç', '~', 0, 0, ']', 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 5
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 6
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 7
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 8
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 9
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 10
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 11
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 12
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 13
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 14
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 15
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 16
};

/* mapa para teclado ABNT2 pt_BR caixa alta */
const char_t	upper_pt_BR[0xFF] =
{
	0, 0, '!', '@', '#', '$', '%', '"', '&', '*', '(', ')', '_', '+', 0, 0, 
	'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 'A', 'S',
	'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Ç', '^', 0, 0, '}', 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 5
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 6
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 7
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 8
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 9
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 10
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 11
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 12
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 13
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 14
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 15
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	// 16
};

void	keyboard_handle(regs_t* r)
{
	uchar_t	scan = in(0x60);
	if(scan & RELEASED)
	{
		switch(scan ^ RELEASED)
		{
			case (KEY_SHIFT):
				shifted = 0;
				break;
			case (KEY_ALT):
				break;
			case (KEY_CTRL):
				controled = 0;
				break;
			default:
				break;
		}
	} else
	{
		switch(scan)
		{
			case KEY_ESC:
				disable();
				kbasic_skip_main(0);
				break;
			case KEY_SHIFT:
				shifted = 1;
				break;
			case KEY_ALT:
				break;
			case KEY_CTRL:
				controled = 1;
				break;
			case KEY_F1:
				if(controled && shifted)
					console_switch(0);
				break;
			case KEY_F2:
				if(controled && shifted)
					console_switch(1);
				break;
			case KEY_F3:
				if(controled && shifted)
					console_switch(2);
				break;
			case KEY_F4:
				if(controled && shifted)
					console_switch(3);
				break;
			default:
				putchar((shifted ? upper_pt_BR : lower_pt_BR)[scan]);
				break;
		}
	}
	lastkey = scan;
	//kprintf("[%d]", scan & 0x000000FF);
}

void	kbasic_install_safe_keyboard()
{
	kprintf("Setting up Generic Safe Keyboard.\n\tESC key to system halt!\n\t[CTRL + SHIFT + FX] to choose console X\n");
	kbasic_irq_setup(1, keyboard_handle);	
}

